package com.bocloud.cmp.service.resource;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import com.alibaba.fastjson.JSONObject;
import com.bocloud.cmp.dao.BeanDetailDao;
import com.bocloud.cmp.dao.ServerDao;
import com.bocloud.cmp.entity.resource.Server;
import com.bocloud.cmp.enums.VMStatus;
import com.bocloud.cmp.interfaces.resource.ServerService;
import com.bocloud.cmp.model.RackDevice;
import com.bocloud.cmp.model.ServerBean;
import com.bocloud.cmp.service.model.OperateResult;
import com.bocloud.cmp.service.utils.ClassHelper;
import com.bocloud.cmp.service.utils.ResourceEventPublisher;
import com.bocloud.cmp.service.utils.ServerHelper;
import com.bocloud.common.ipmi.IPMIClient;
import com.bocloud.common.model.BsmResult;
import com.bocloud.common.model.GridBean;
import com.bocloud.common.model.Param;
import com.bocloud.common.model.Result;
import com.bocloud.common.model.SimpleBean;
import com.bocloud.common.ssh.SSH;
import com.bocloud.common.utils.GridHelper;
import com.bocloud.coordinator.harmony.HarmonyLock;
import com.bocloud.coordinator.harmony.LockFactory;
import com.veraxsystems.vxipmi.coding.commands.chassis.PowerCommand;

/**
 * 主机抽象Service接口实现类
 * 
 * @author wei wei
 * @version 1.0
 * @since 2016.02.27
 */
@Service("serverService")
public class ServerServiceImpl implements ServerService {

	private static Logger logger = LoggerFactory.getLogger(ServerServiceImpl.class);
	@Autowired
	private ServerDao serverDao;
	@Autowired
	private BeanDetailDao beanDetailDao;
	@Autowired
	private LockFactory lockFactory;
	@Autowired
	private ResourceEventPublisher resourceEventPublisher;

	@Override
	public BsmResult exists(String ip) {
		try {
			boolean result = this.serverDao.exists(ip);
			if (result) {
				return new BsmResult(true, "IP存在");
			}
			return new BsmResult(false, "IP不存在");
		} catch (Exception e) {
			logger.error("Check vm ip fail:", e);
			return new BsmResult(false, "确定vm ip是否存在失败");
		}
	}

	@Override
	public BsmResult create(Server server, Long userId) {
		try {
			if (null == server) {
				logger.warn("Server parameters error!");
				return new BsmResult(false, "添加失败");
			}

			if (this.serverDao.exists(server.getManagerIp())) {
				logger.warn("Server IP has exist！");
				return new BsmResult(false, "IP已存在");
			}

			BsmResult result = ServerHelper.fromSSH(server.getOsAccount(), server.getOsPassword(),
					server.getManagerIp(), server.getManagerPort(), logger);
			if (result.isSuccess()) {
				Server object = (Server) result.getData();
				server = (Server) ClassHelper.merger(server, object);
			} else {
				return result;
			}
			server.setCreaterId(userId);
			server.setMenderId(userId);
			server.setStatus(VMStatus.RUNNING.name());
			server.setConditions("RUNNING");
			server.setPlatform("私有平台");
			server.setIsAllot(false);
			serverDao.save(server);
			Integer cpu = server.getProcessorAmount();
			Integer memory = server.getMemoryCapacity();
			Integer disk = server.getDiskCapacity();
			if (null == cpu) {
				cpu = 0;
			}
			if (null == memory) {
				memory = 0;
			}
			if (null == disk) {
				disk = 0;
			}
		} catch (Exception e) {
			logger.error("Create server fail:", e);
			return new BsmResult(false, "添加失败");
		}
		return new BsmResult(true, server, "添加成功");
	}

	@Override
	public BsmResult modify(ServerBean bean, Long userId) {
		String path = Server.class.getSimpleName() + "_" + bean.getId();
		HarmonyLock lock = null;
		SSH ssh = null;
		try {
			lock = lockFactory.getLock(path);
			if (!lock.acquire(path, 10, TimeUnit.SECONDS)) {
				logger.warn("Get harmonyLock time out!");
				return new BsmResult(false, "请求超时", "", "");
			}

			Server server = this.serverDao.query(bean.getId());
			if (null == server) {
				logger.warn("Server does not exist!");
				return new BsmResult(false, "数据不存在", "", "");
			}

			if (!StringUtils.hasText(bean.getManagerPort() + "")) {
				ssh = new SSH(bean.getManagerIp(), bean.getOsAccount(), bean.getOsPassword());
			} else {
				ssh = new SSH(bean.getManagerIp(), bean.getOsAccount(), bean.getOsPassword(), bean.getManagerPort());
			}

			if (!ssh.connect()) {
				logger.warn("Server username or password error!");
				return new BsmResult(false, "服务器地址端口、用户账号或密码错误");
			}

			BeanUtils.copyProperties(bean, server);
			server.setMenderId(userId);
			this.serverDao.update(server);
			return new BsmResult(true, "修改成功");
		} catch (Exception e) {
			logger.error("Modify server fail:", e);
			return new BsmResult(false, "修改失败");
		} finally {
			if (null != ssh) {
				ssh.close();
			}
			if (null != lock) {
				lock.release();
			}
		}
	}

	@Override
	public BsmResult remove(Long id, Long userId) {
		String path = Server.class.getSimpleName() + "_" + id;
		HarmonyLock lock = null;
		boolean result = false;
		try {
			lock = lockFactory.getLock(path);
			if (!lock.acquire(path, 10, TimeUnit.SECONDS)) {
				logger.warn("Get harmonyLock time out!");
				return new BsmResult(false, "请求超时", "", "");
			}
			Server server = this.serverDao.query(id);
			if (null == server) {
				logger.warn("Server does not exist!");
				return new BsmResult(false, "数据不存在", "", "");
			}
			result = this.serverDao.remove(id, userId);
		} catch (Exception e) {
			logger.error("Remove server fail:", e);
			return new BsmResult(false, "删除失败");
		} finally {
			if (null != lock) {
				lock.release();
			}
		}
		return result ? new BsmResult(true, "删除成功") : new BsmResult(false, "删除失败", "", "");
	}

	@Override
	public BsmResult basic(Long id) {
		Server server = null;
		try {
			server = this.beanDetailDao.getServerBean(id);
			if (null == server) {
				logger.warn("Server does not exist!");
				return new BsmResult(false, server, "该服务器不存在");
			}
		} catch (Exception e) {
			logger.error("Query server fail:", e);
			return new BsmResult(false, "查询失败");
		}
		return new BsmResult(true, server, "查询成功");
	}

	@Override
	public BsmResult list(int page, int rows, List<Param> params, Map<String, String> sorter, Boolean simple) {
		List<Server> list = null;
		List<SimpleBean> beans = null;
		int total = 0;
		GridBean gridBean = null;
		try {
			total = this.serverDao.count(params);
			if (simple) {
				beans = this.serverDao.list(params, sorter);
				gridBean = new GridBean(1, 1, total, beans);
			} else {
				list = this.serverDao.list(page, rows, params, sorter);
				gridBean = GridHelper.getBean(page, rows, total, list);
			}
			return new BsmResult(true, gridBean, "查询成功");
		} catch (Exception e) {
			logger.error("Query server list fail:", e);
			return new BsmResult(false, "查询失败");
		}
	}

	@Override
	public BsmResult detail(Long id) {
		Server server = null;
		try {
			if (id == 0) {
				server = new Server();
				server.setServers(this.serverDao.count(null));
			} else {
				server = this.beanDetailDao.getServerBean(id);
				if (null == server) {
					logger.warn("Server does not exist!");
					return new BsmResult(true, server, "该服务器不存在");
				}
			}
		} catch (Exception e) {
			logger.error("Query server detail fail:", e);
			return new BsmResult(false, "查询失败");
		}
		return new BsmResult(true, server, "查询成功");
	}

	@Override
	public BsmResult inRack(RackDevice rackDevice, Long userId) {
		String path = Server.class.getSimpleName() + "_" + rackDevice.getDeviceId();
		HarmonyLock lock = null;
		try {
			lock = lockFactory.getLock(path);
			if (!lock.acquire(path, 10, TimeUnit.SECONDS)) {
				logger.warn("Get harmonyLock time out!");
				return new BsmResult(false, "请求超时", "", "");
			}
			this.serverDao.belong(rackDevice, userId);
			return new BsmResult(true, "添加成功");
		} catch (Exception e) {
			logger.error("Assign rack to server fail:", e);
			return new BsmResult(false, "添加失败", "", "");
		} finally {
			if (null != lock) {
				lock.release();
			}
		}
	}

	@Override
	public BsmResult outRack(Long id, Long userId) {
		String path = Server.class.getSimpleName() + "_" + id;
		HarmonyLock lock = null;
		try {
			lock = lockFactory.getLock(path);
			if (!lock.acquire(path, 10, TimeUnit.SECONDS)) {
				logger.warn("Get harmonyLock time out!");
				return new BsmResult(false, "请求超时", "", "");
			}
			this.serverDao.release(id, userId);
			return new BsmResult(true, "移除成功");
		} catch (Exception e) {
			logger.error("Free server from rack fail:", e);
			return new BsmResult(false, "移除失败", "", "");
		} finally {
			if (null != lock) {
				lock.release();
			}
		}
	}

	@Override
	public BsmResult freePMs() {
		List<Server> list = null;
		try {
			list = this.serverDao.listFree();
		} catch (Exception e) {
			logger.error("Query free server list fail:", e);
			return new BsmResult(false, "");
		}
		return new BsmResult(true, list, "查询成功");
	}

	@Override
	public BsmResult start(Long id, Long userId) {
		String path = Server.class.getSimpleName() + "_" + id;
		HarmonyLock lock = null;
		try {
			lock = lockFactory.getLock(path);
			if (!lock.acquire(path, 10, TimeUnit.SECONDS)) {
				logger.warn("Get harmonyLock time out!");
				return new BsmResult(false, "请求超时", "", "");
			}
			Server server = this.beanDetailDao.getServerBean(id);
			if (null == server) {
				logger.warn("Server does not exist!");
				return new BsmResult(false, server, "该服务器不存在");
			}
			if (!StringUtils.hasText(server.getIpmiAddress()) || !StringUtils.hasText(server.getIpmiAccount())
					|| !StringUtils.hasText(server.getIpmiPassword())) {
				return new BsmResult(false, "IPMI地址、账户或密码为空");
			}
			IPMIClient ipmiClient = new IPMIClient(server.getIpmiAddress(), server.getIpmiAccount(),
					server.getIpmiPassword(), server.getIpmiPort());
			Result result = ipmiClient.action(PowerCommand.PowerUp);
			if (result.isSuccess()) {
				server.setStatus(VMStatus.RUNNING.name());
				serverDao.update(server);
			}
			return result.isSuccess() ? new BsmResult(true, "启动成功") : new BsmResult(false, "启动失败");
		} catch (Exception e) {
			logger.error("Start server fail:", e);
			return new BsmResult(false, "启动失败");
		} finally {
			if (null != lock) {
				lock.release();
			}
		}
	}

	@Override
	public BsmResult stop(Long id, Long userId) {
		String path = Server.class.getSimpleName() + "_" + id;
		HarmonyLock lock = null;
		try {
			lock = lockFactory.getLock(path);
			if (!lock.acquire(path, 10, TimeUnit.SECONDS)) {
				logger.warn("Get harmonyLock time out!");
				return new BsmResult(false, "请求超时", "", "");
			}
			Server server = this.beanDetailDao.getServerBean(id);
			if (null == server) {
				logger.warn("Server does not exist!");
				return new BsmResult(false, server, "该服务器不存在");
			}
			if (!StringUtils.hasText(server.getIpmiAddress()) || !StringUtils.hasText(server.getIpmiAccount())
					|| !StringUtils.hasText(server.getIpmiPassword()) || null != server.getIpmiPort()) {
				return new BsmResult(false, "IPMI地址、账户、密码或端口为空");
			}
			IPMIClient ipmiClient = new IPMIClient(server.getIpmiAddress(), server.getIpmiAccount(),
					server.getIpmiPassword(), server.getIpmiPort());
			Result result = ipmiClient.action(PowerCommand.PowerDown);
			if (result.isSuccess()) {
				server.setStatus(VMStatus.STOPPED.name());
				serverDao.update(server);
			}
			return result.isSuccess() ? new BsmResult(true, "关闭成功") : new BsmResult(false, "关闭失败");
		} catch (Exception e) {
			logger.error("Stop server fail:", e);
			return new BsmResult(false, "关闭失败");
		} finally {
			if (null != lock) {
				lock.release();
			}
		}
	}

	@Override
	public BsmResult restart(Long id, Long userId) {
		try {
			Server server = this.beanDetailDao.getServerBean(id);
			if (null == server) {
				logger.warn("Server does not exist!");
				return new BsmResult(false, server, "该服务器不存在");
			}
			if (!StringUtils.hasText(server.getIpmiAddress()) || !StringUtils.hasText(server.getIpmiAccount())
					|| !StringUtils.hasText(server.getIpmiPassword())) {
				return new BsmResult(false, "IPMI地址、账户或密码为空");
			}
			IPMIClient ipmiClient = new IPMIClient(server.getIpmiAddress(), server.getIpmiAccount(),
					server.getIpmiPassword(), server.getIpmiPort());
			Result result = ipmiClient.action(PowerCommand.PowerDown);
			if (result.isSuccess()) {
				result = ipmiClient.action(PowerCommand.PowerUp);
			}
			return result.isSuccess() ? new BsmResult(true, "重启成功") : new BsmResult(false, "重启失败");
		} catch (Exception e) {
			logger.error("Restart server fail:", e);
			return new BsmResult(false, "重启失败");
		}

	}

	@Override
	public BsmResult isolate(Long id, Long userId) {
		String path = Server.class.getSimpleName() + "_" + id;
		HarmonyLock lock = null;
		try {
			lock = lockFactory.getLock(path);
			if (!lock.acquire(path, 10, TimeUnit.SECONDS)) {
				logger.warn("Get harmonyLock time out!");
				return new BsmResult(false, "请求超时", "", "");
			}
			this.serverDao.isolate(id, userId);
			return new BsmResult(true, "隔离成功");
		} catch (Exception e) {
			logger.error("Isolate server fail:", e);
			return new BsmResult(false, "隔离失败");
		} finally {
			if (null != lock) {
				lock.release();
			}
		}
	}

	@Override
	public BsmResult recover(Long id, Long userId) {
		String path = Server.class.getSimpleName() + "_" + id;
		HarmonyLock lock = null;
		try {
			lock = lockFactory.getLock(path);
			if (!lock.acquire(path, 10, TimeUnit.SECONDS)) {
				logger.warn("Get harmonyLock time out!");
				return new BsmResult(false, "请求超时", "", "");
			}
			this.serverDao.recover(id, userId);
			return new BsmResult(true, "恢复成功");
		} catch (Exception e) {
			logger.error("Recover server fail:", e);
			return new BsmResult(false, "恢复失败");
		} finally {
			if (null != lock) {
				lock.release();
			}
		}
	}

	public static JSONObject getJson(String result) {
		JSONObject json = new JSONObject();
		String[] data = result.split("\n");
		String tag = ":";
		for (String str : data) {
			String[] value = str.split(tag);
			json.put(value[0], value[1]);
		}
		return json;
	}

	/**
	 * 通过IP查询当前主机信息
	 * 
	 * @author sxp
	 * @since V1.0 Nov 4, 2016
	 */
	@Override
	public Server detail(String ip) {
		Server server = null;

		try {
			server = this.serverDao.get(ip);
		} catch (Exception e) {
			logger.error("Query server information by IP fail.", e);
		}

		return server;
	}

	/**
	 * 当前主机的操作系统是否为Windows
	 * <p>
	 * 目前调用该方法的地方：监控查询时判断主机是否为Windows系统，Windows有单独的查询方法
	 * </p>
	 * 
	 * @author sxp
	 * @since V1.0 Nov 4, 2016
	 */
	@Override
	public boolean isWindowsPlatform(Long id) {
		// 虽然【主机管理】功能中没有维护操作系统名称的地方，但是数据库表server中有os_name这个字段
		Server server = null;

		try {
			server = this.serverDao.query(id);
		} catch (Exception e) {
			logger.error("Query server information by id fail.", e);
		}

		if (server == null) {
			return false;
		}

		String osName = server.getOsName();
		if (!StringUtils.hasText(osName)) {
			return false;// 没有维护操作系统名称，认为非Windows
		}

		osName = osName.toLowerCase();
		if (osName.contains("windows") || osName.contains("win")) {
			return true;
		} else {
			return false;
		}
	}

	@Override
	public List<Map<String, String>> getAll4Snmp() {
		try {
			return this.serverDao.getAll4Snmp();
		} catch (Exception e) {
			logger.error(":", e);
			return new ArrayList<>();
		}
	}

	@Override
	public BsmResult batchStart(String params, Long userId) {
		String[] idArray = params.split(",");// 获取要停止的虚拟机的id
		new Thread(new Runnable() {
			@Override
			public void run() {
				String operate = "platform.server";
				try {
					String failServerName = "";
					if (null != idArray && idArray.length != 0) {
						for (String id : idArray) {
							Server server = serverDao.query(Long.parseLong(id));
							if (!"STOPPED".equalsIgnoreCase(server.getStatus())) {
								continue;
							}
							BsmResult result = start(Long.parseLong(id), userId);// 停止物理机
							if (!result.isSuccess()) {// 该物理机停止失败
								// 查询停止失败的物理机
								server = serverDao.query(Long.parseLong(id));
								failServerName += server.getName() + " ";
							}
						}
					}
					if (failServerName.equals("")) {
						resourceEventPublisher.send(new OperateResult(true, "批量启动成功", operate));
					} else {
						resourceEventPublisher.send(new OperateResult(false, failServerName + "启动失败", operate));
					}
				} catch (Exception e) {
					logger.error("batch stop server fail:", e);
					resourceEventPublisher.send(new OperateResult(false, "批量启动失败", operate));
				}
			}
		}).start();
		return new BsmResult(true, "批量启动任务已执下发，正在执行...");
	}

	@Override
	public BsmResult batchStop(String params, Long userId) {
		String[] idArray = params.split(",");// 获取要停止的虚拟机的id
		new Thread(new Runnable() {
			@Override
			public void run() {
				String operate = "platform.server";
				try {
					String failServerName = "";
					if (null != idArray && idArray.length != 0) {
						for (String id : idArray) {
							Server server = serverDao.query(Long.parseLong(id));
							if (!"RUNNING".equalsIgnoreCase(server.getStatus())) {
								continue;
							}
							BsmResult result = stop(Long.parseLong(id), userId);// 停止物理机
							if (!result.isSuccess()) {// 该物理机停止失败
								// 查询停止失败的物理机
								server = serverDao.query(Long.parseLong(id));
								failServerName += server.getName() + " ";
							}
						}
					}
					if (failServerName.equals("")) {
						resourceEventPublisher.send(new OperateResult(true, "批量停止成功", operate));
					} else {
						resourceEventPublisher.send(new OperateResult(false, failServerName + "停止失败", operate));
					}
				} catch (Exception e) {
					logger.error("batch stop server fail:", e);
					resourceEventPublisher.send(new OperateResult(false, "批量停止失败", operate));
				}
			}
		}).start();
		return new BsmResult(true, "批量停止任务已执下发，正在执行...");
	}

	@Override
	public BsmResult batchRemove(String params, Long userId) {
		String[] idArray = params.split(",");// 获取要删除的物理机的id
		try {
			// 失败物理机机名称
			String failServerName = "";
			if (null != idArray && idArray.length > 0) {
				for (String id : idArray) {
					BsmResult result = remove(Long.parseLong(id), userId);// 删除物理机
					if (!result.isSuccess()) {// 该物理机删除失败
						// 查询删除失败的物理机
						Server server = serverDao.query(Long.parseLong(id));
						failServerName += server.getName() + " ";
					}
				}
			}
			if (failServerName.equals("")) {
				return new BsmResult(true, "批量删除成功");
			} else {
				return new BsmResult(false, failServerName + "删除失败");
			}
		} catch (Exception e) {
			logger.error("batch remove server fail:", e);
			return new BsmResult(false, "删除失败");
		}
	}

}